package fractal;

import java.util.Stack;

import entity.Position;

public class TerrainMap
{
  protected Terrain[][] _Map;

  public TerrainMap(int pTaille)
  {
    init(pTaille);

  }

  public void generateWorld()
  {
    generateHauteur();
    generateTemperature();
    generateHumidite();
    //generateForest();
    //riviere 
    GenerateurRiviere.generateRiver(this,5);
  }

  public void generateHauteur()
  {
    GenerateurFractal gen = new GenerateurFractal();
    gen.generateFractal("SIMHA", _Map.length);
    double[][] map = gen.getMap();
    for (int i = 0; i < _Map.length; i++)
    {
      for (int j = 0; j < _Map.length; j++)
      {
        _Map[i][j].setHauteur(map[i][j]);
      }
    }
  }

  public void generateTemperature()
  {
    GenerateurFractal gen = new GenerateurFractal();
    gen.generateFractal("SIMTE", _Map.length);
    double[][] map = gen.getMap();
    for (int i = 0; i < _Map.length; i++)
    {
      for (int j = 0; j < _Map.length; j++)
      {
        _Map[i][j].setTemperature(map[i][j]);
      }
    }
  }
  
  public void generateHumidite()
  {
    GenerateurFractal gen = new GenerateurFractal();
    gen.generateFractal("SIMHU", _Map.length);
    double[][] map = gen.getMap();
    for (int i = 0; i < _Map.length; i++)
    {
      for (int j = 0; j < _Map.length; j++)
      {
        _Map[i][j].setHumidite(map[i][j]);
      }
    }
  }

  public void generateForest()
  {
    GenerateurFractal gen = new GenerateurFractal();
    gen.generateFractal("SIMFO", _Map.length);
    double[][] map = gen.getMap();

    for (int i = 0; i < _Map.length; i++)
    {
      for (int j = 0; j < _Map.length; j++)
      {
        TerrainType type = _Map[i][j].getTerrainType();
        if (TerrainType.MOUNTAIN.equals(type))
        {
          _Map[i][j].setForest(map[i][j] < 10);
        }
        else if (TerrainType.PLAT.equals(type))
        {
          _Map[i][j].setForest(map[i][j] < 35);
        }
        else if (TerrainType.SNOW.equals(type))
        {
          _Map[i][j].setForest(map[i][j] < 10);
        }
      }
    }
  }

  public void generateCity()
  {
    Randomiseur random = new Pseudoalea("CITY");
    double[][] map = new double[_Map.length][_Map.length];
    for (int i = 0; i < map.length; i++)
    {
      for (int j = 0; j < map.length; j++)
      {
        TerrainType type = _Map[i][j].getTerrainType();
        int indice = 0;
        if (TerrainType.PLAT.equals(type))
        {
          indice = 50;
        }
        else if (TerrainType.MOUNTAIN.equals(type))
        {
          indice = 20;
        }
        map[i][j] = indice;
      }
    }
    int nbCity = 0;
    int indice = 50;
    int nbVille = 10000;
    while (nbCity < nbVille && indice > 30)
    {
      for (int i = 0; i < map.length && nbCity < nbVille; i++)
      {
        for (int j = 0; j < map.length && nbCity < nbVille; j++)
        {
          if (map[i][j] >= indice && !_Map[i][j].isCity())
          {
            if (((int)(random.random() * 30)) == 0)
            {
              _Map[i][j].setCity(true);
              map[i][j] = map[i][j] - 50;
              nbCity++;
              decrementCity(map, i, j, 1, 40);
              decrementCity(map, i, j, 2, 35);
              decrementCity(map, i, j, 3, 30);
              decrementCity(map, i, j, 4, 25);
              decrementCity(map, i, j, 5, 20);
              decrementCity(map, i, j, 6, 15);
              decrementCity(map, i, j, 7, 10);
            }
          }
        }
      }
      indice = indice - 2;
    }

  }

  protected void decrementCity(double[][] map, int x, int y, int cercle, double decremente)
  {
    for (int i = -cercle; i <= cercle; i++)
    {
      for (int j = -cercle; j <= cercle; j++)
      {
        if ((x + i == x - cercle || x + i == x + cercle || y + j == y - cercle || y + j == y + cercle) && x + i >= 0 && x + i < map.length && y + j >= 0 && y + j < map.length)
        {
          map[x + i][y + j] = map[x + i][y + j] - decremente;
        }
      }
    }
  }

  public void generateEmpire()
  {
    Randomiseur random = new Pseudoalea("CITY");
    int nbEmpire = 0;
    int nbMaxEmpire = 100;
    for (int nb = 0; nb < 3 && nbEmpire < nbMaxEmpire; nb++)
    {
      for (int i = 0; i < _Map.length && nbEmpire < nbMaxEmpire; i++)
      {
        for (int j = 0; j < _Map.length && nbEmpire < nbMaxEmpire; j++)
        {
          Terrain ter = _Map[i][j];
          if (ter.getEmpire() == -1 && ter.isCity())
          {
            // System.out.println(ter.getEmpire() );
            createEmpire(i, j, nbEmpire, random);
            nbEmpire++;
          }
        }
      }
    }
  }

  protected void createEmpire(int x, int y, int nbEmpire, Randomiseur random)
  {
    Stack<Position> pile = new Stack<Position>();
    pile.add(new Position(x, y));
    _Map[x][y].setEmpire(nbEmpire);
    _Map[x][y].setIndiceEmpire(150 - (int)(random.random() * 125));
    while (!pile.isEmpty())
    {
      Position p = pile.pop();
      Terrain current = _Map[p.getX()][p.getY()];
      if (current.getIndiceEmpire() > 0)
      {
        if (p.getY() + 1 < _Map.length)
        {
          manageEmpire(p.getX(), p.getY() + 1, pile, nbEmpire, current);
        }
        if (p.getX() + 1 < _Map.length)
        {
          manageEmpire(p.getX() + 1, p.getY(), pile, nbEmpire, current);
        }

        if (p.getX() - 1 >= 0)
        {
          manageEmpire(p.getX() - 1, p.getY(), pile, nbEmpire, current);
        }
        if (p.getY() - 1 >= 0)
        {
          manageEmpire(p.getX(), p.getY() - 1, pile, nbEmpire, current);
        }
      }

    }
  }

  protected void manageEmpire(int i, int j, Stack<Position> pPile, int nbEmpire, Terrain current)
  {
    Terrain next = _Map[i][j];
    int indiceTerrain = -1;
    if (TerrainType.WATER.equals(next.getTerrainType()))
    {
      indiceTerrain = -2;
    }
    else if (TerrainType.MOUNTAIN.equals(next.getTerrainType()))
    {
      indiceTerrain = -3;
    }
    else if (TerrainType.CITY.equals(next.getTerrainType()))
    {
      indiceTerrain = 6;
    }
    if (next.getEmpire() == -1)
    {
      _Map[i][j].setEmpire(nbEmpire);

      _Map[i][j].setIndiceEmpire(current.getIndiceEmpire() + indiceTerrain);

      pPile.add(new Position(i, j));
    }
    else if (next.getEmpire() == current.getEmpire() && next.getIndiceEmpire() + indiceTerrain > current.getIndiceEmpire())
    {
      _Map[i][j].setIndiceEmpire(next.getIndiceEmpire() + indiceTerrain);
      pPile.add(new Position(i, j));
    }

  }

  protected void init(int pTaille)
  {
    _Map = new Terrain[pTaille][pTaille];
    for (int i = 0; i < pTaille; i++)
    {
      for (int j = 0; j < pTaille; j++)
      {
        _Map[i][j] = new Terrain();
      }
    }
  }

  public Terrain[][] getMap()
  {
    return _Map;
  }

  // protected void lissage() {
  // Terrain[][] map = new Terrain[_Map.length][_Map.length];
  // for (int i = 0; i < map.length; i++)
  // {
  // for (int j = 0; j < map.length; j++)
  // {
  // _Map[i][j] = new Terrain();
  // int v1 = calculV1(i, j);
  // int v2 = calculV2(i, j);
  // if (v1 < 4)
  // {
  //
  // }
  // }
  // }
  // }
  //
  // protected int calculV1(int i, int j) {
  // TerrainType type = _Map[i][j].getTerrainType();
  // int nb = 0;
  // if (i + 1 < _Map.length)
  // {
  // nb = nb + (type.equals(_Map[i + 1][j].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (j + 1 < _Map.length
  // && type.equals(_Map[i + 1][j + 1].getTerrainType()) ? 1
  // : 0);
  // nb = nb
  // + (j - 1 >= 0
  // && type.equals(_Map[i + 1][j - 1].getTerrainType()) ? 1
  // : 0);
  // }
  // nb = nb
  // + (j - 1 >= 0 && type.equals(_Map[i][j - 1].getTerrainType()) ? 1
  // : 0);
  // nb = nb
  // + (j + 1 < _Map.length
  // && type.equals(_Map[i][j + 1].getTerrainType()) ? 1 : 0);
  // if (i - 1 >= 0)
  // {
  // nb = nb + (type.equals(_Map[i - 1][j].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (j - 1 >= 0
  // && type.equals(_Map[i - 1][j - 1].getTerrainType()) ? 1
  // : 0);
  // nb = nb
  // + (j + 1 < _Map.length
  // && type.equals(_Map[i - 1][j + 1].getTerrainType()) ? 1
  // : 0);
  // }
  // return nb;
  // }
  //
  // protected double somme(int i, int j) {
  // TerrainType type = _Map[i][j].getTerrainType();
  // int somme = 0;
  // if (i + 1 < _Map.length)
  // {
  // somme += _Map[i + 1][j].getTemperature();
  // somme += (j + 1 < _Map.length
  // && type.equals(_Map[i + 1][j + 1].getTerrainType()) ? 1 : 0);
  // somme += (j - 1 >= 0
  // && type.equals(_Map[i + 1][j - 1].getTerrainType()) ? 1 : 0);
  // }
  // somme += (j - 1 >= 0 && type.equals(_Map[i][j - 1].getTerrainType()) ? 1
  // : 0);
  // somme += (j + 1 < _Map.length
  // && type.equals(_Map[i][j + 1].getTerrainType()) ? 1 : 0);
  // if (i - 1 >= 0)
  // {
  // somme += (type.equals(_Map[i - 1][j].getTerrainType()) ? 1 : 0);
  // somme += (j - 1 >= 0
  // && type.equals(_Map[i - 1][j - 1].getTerrainType()) ? 1 : 0);
  // somme += (j + 1 < _Map.length
  // && type.equals(_Map[i - 1][j + 1].getTerrainType()) ? 1 : 0);
  // }
  // return somme;
  // }
  //
  // protected int calculV2(int i, int j) {
  // TerrainType type = _Map[i][j].getTerrainType();
  // int nb = calculV1(i, j);
  // if (i + 2 < _Map.length)
  // {
  // nb = nb + (type.equals(_Map[i + 2][j].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (j + 1 < _Map.length
  // && type.equals(_Map[i + 2][j + 1].getTerrainType()) ? 1
  // : 0);
  // nb = nb
  // + (j - 1 >= 0
  // && type.equals(_Map[i + 2][j - 1].getTerrainType()) ? 1
  // : 0);
  // }
  // if (i - 2 >= 0)
  // {
  // nb = nb + (type.equals(_Map[i - 2][j].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (j + 1 < _Map.length
  // && type.equals(_Map[i - 2][j + 1].getTerrainType()) ? 1
  // : 0);
  // nb = nb
  // + (j - 1 >= 0
  // && type.equals(_Map[i - 2][j - 1].getTerrainType()) ? 1
  // : 0);
  // }
  // if (j + 2 < _Map.length)
  // {
  // nb = nb
  // + (i - 1 >= 0
  // && type.equals(_Map[i - 1][j + 2].getTerrainType()) ? 1
  // : 0);
  // nb = nb + (type.equals(_Map[i][j + 2].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (i + 1 < _Map.length
  // && type.equals(_Map[i + 1][j + 2].getTerrainType()) ? 1
  // : 0);
  // }
  // if (j - 2 >= 0)
  // {
  // nb = nb
  // + (i - 1 >= 0
  // && type.equals(_Map[i - 1][j - 2].getTerrainType()) ? 1
  // : 0);
  // nb = nb + (type.equals(_Map[i][j - 2].getTerrainType()) ? 1 : 0);
  // nb = nb
  // + (i + 1 < _Map.length
  // && type.equals(_Map[i + 1][j - 2].getTerrainType()) ? 1
  // : 0);
  // }
  // return nb;
  // }
}
